﻿#pragma once

#include <type_traits>

#define HAS_MEMBER_FUNCTION_DEFINE(member)                                                                       \
    template <typename T, typename... Args>                                                                      \
    struct HasMemberFunction_##member                                                                            \
    {                                                                                                            \
    private:                                                                                                     \
        template <typename U>                                                                                    \
        static auto Check(int) -> decltype(std::declval<U>().member(std::declval<Args>()...), std::true_type()); \
        template <typename U>                                                                                    \
        static std::false_type Check(...);                                                                       \
                                                                                                                 \
    public:                                                                                                      \
        enum                                                                                                     \
        {                                                                                                        \
            value = std::is_same<decltype(Check<T>(0)), std::true_type>::value                                   \
        };                                                                                                       \
    };

#define HAS_MEMBER_TYPE_DEFINE(member)                                                  \
    template <typename T, typename = void>                                              \
    struct HasMemberType_##member : std::false_type                                     \
    {                                                                                   \
    };                                                                                  \
    template <typename T>                                                               \
    struct HasMemberType_##member<T, nggs::void_t<typename T::member>> : std::true_type \
    {                                                                                   \
    };

namespace nggs
{
#if __cplusplus >= 201402L
    // using decay_t = std::decay_t;
    // using void_t = std::void_t;
    // using index_sequence = std::index_sequence;
    // using make_index_sequence = std::make_index_sequence;

#elif __cplusplus >= 201103L || _MSC_VER == 1800
    template <typename T>
    using decay_t = typename std::decay<T>::type;

    template <typename... Ts>
    struct make_void
    {
        using type = void;
    };

    template <typename... Ts>
    using void_t = typename make_void<Ts...>::type;

    template <std::size_t... Indexes>
    struct index_sequence
    {
    };

    template <std::size_t Index, std::size_t... Indexes>
    struct make_index_sequence : make_index_sequence<Index - 1, Index - 1, Indexes...>
    {
    };

    template <std::size_t... Indexes>
    struct make_index_sequence<0, Indexes...> : index_sequence<Indexes...>
    {
    };

    //#else
    //    static_assert(true, "please use c++11 or higher")
#endif
} // namespace nggs
